// day60s.ts
import { Context, h, Logger } from "koishi";
import { PLUGIN_NAME, POWERED_BY_STR } from "./index";
import { MESSSAGE_FORM } from "./type";
import { getGoogleImages } from "./google-api";
import { } from 'koishi-plugin-puppeteer';
import { formatDateTime } from "./utils";
import cron, { ScheduledTask } from 'node-cron';


// 声明新的数据库表
declare module 'koishi' {
  interface Tables {
    day60s_image_cache: Day60sImageCache
  }
}

// 定义数据表的类型接口，imageUrl 现在是可选的
interface Day60sImageCache {
  keyword: string;
  imageUrl: string;
  insertTime: number;
}

interface NewsItemWithImage {
  text: string;
  imageUrl?: string;
}

export function day60s(ctx: Context, config: any) {
  const day60sLogger = new Logger(`${PLUGIN_NAME}-day60s`);

  // 扩展数据库模型，定义新的表
  ctx.model.extend('day60s_image_cache', {
    keyword: 'string',
    imageUrl: 'string',
    insertTime: 'integer',
  }, {
    primary: 'keyword', // 将 keyword 设为主键
    unique: ['keyword']
  });

  ctx.command('day60s', '获取每日60秒早报')
    .alias('早报').alias('60s早报')
    .action(async ({ session }) => {


      try {

        let newsMessage;
        const hintMsgId = await session.send(`${h.quote(session.messageId)}正在获取今日60秒早报，请稍候...`);

        if (config.day60s.messageForm === MESSSAGE_FORM.TEXT) {
          newsMessage = await formatNewsAsTextWithImage(config, config.day60s.commandWithGoogleImage); //newsMessage is Array<h>
        }
        if (config.day60s.messageForm === MESSSAGE_FORM.IMAGE) {
          newsMessage = await formatNewsAsImage(config, config.day60s.commandWithGoogleImage); //newsMessage is Array<h>
        }
        if (config.day60s.messageForm === MESSSAGE_FORM.FORWARD) {
          newsMessage = await formatNewsAsForward(config, config.day60s.commandWithGoogleImage); //newsMessage is string
        }

        if (config.day60s.enableQuoteSessionMessage) {
          if (config.day60s.messageForm !== MESSSAGE_FORM.FORWARD) {
            newsMessage = [h.quote(session.messageId), ...newsMessage];
            //newsMessage is still Array<h>
          } else {
            //newsMessage is still string
          }
        }

        await session.send(newsMessage);

        await session.bot.deleteMessage(session.channelId, hintMsgId[0]);

      } catch (e) {
        const errMsg = `抱歉，获取day60s早报失败，请稍后再试。错误: ${e.message}`;
        day60sLogger.error(errMsg);
        await session.send(errMsg);
      }
    })

  ctx.command('day60s.refresh-image-db', '刷新图片数据库缓存')
    .action(async ({ session }) => {
      const day60sLogger = new Logger(`${PLUGIN_NAME}-day60s`);
      try {
        await session.send('正在刷新图片缓存，请稍候...');

        // 1. 获取最新新闻列表
        const newsList = await getDay60sNews();
        const now = Date.now();
        let updatedCount = 0;
        let failedCount = 0;

        // 2. 遍历新闻，为每条新闻重新获取并更新图片
        for (const item of newsList) {
          // 跳过特定新闻
          if (item.text === '今天的简讯未更新，下面是昨天的简讯！') {
            continue;
          }

          try {
            const imageSearchRes = await getGoogleImages(ctx, config.googleApi.baseUrl, item.text, config.googleApi.apiKey, config.googleApi.searchEngineId, 1, 10, 'zh-CN');
            const imageUrl = imageSearchRes?.items?.[0]?.link;

            if (imageUrl) {
              // 如果成功获取到新图片，则更新数据库
              await ctx.database.upsert('day60s_image_cache', [{
                keyword: item.text,
                imageUrl: `${config.googleApi.baseUrl}/image_proxy?url=${imageUrl}`,
                insertTime: now
              }]);
              updatedCount++;
            } else {
              day60sLogger.warn(`为新闻"${item.text}"获取图片失败，未找到结果。`);
              failedCount++;
            }
          } catch (e) {
            day60sLogger.error(`为新闻"${item.text}"获取图片失败: ${e.message}`);
            failedCount++;
          }
          // 增加延时，避免触发Google API速率限制
          await new Promise(resolve => setTimeout(resolve, 500));
        }

        // 3. 结果反馈
        if (updatedCount > 0) {
          await session.send(`图片缓存刷新完毕。成功更新 ${updatedCount} 条新闻图片，${failedCount} 条失败。`);
        } else {
          await session.send(`图片缓存刷新完毕，但未能获取到任何新图片。请检查API配置或稍后再试。`);
        }

      } catch (e) {
        day60sLogger.error(`刷新图片数据库失败: ${e.message}`);
        await session.send(`刷新图片数据库失败，请稍后再试。错误: ${e.message}`);
      }
    });

  async function getDay60sNews(): Promise<Array<{ text: string; search_url: string }>> {
    const newsRes = await ctx.http.get<any>(`${config.day60s.baseUrl}?format=json`);
    day60sLogger.info(`获取到的早报数据: ${JSON.stringify(newsRes)}`);

    const newsList = newsRes?.news || [];

    if (!Array.isArray(newsList) || newsList.length === 0) {
      throw new Error('未能获取到最新的早报信息。');
    }

    return newsList;
  }

  // 辅助函数：清理过期缓存
  async function cleanUpExpiredImageCache() {
    const cacheExpireTime = 48 * 60 * 60 * 1000; // 48小时（毫秒）
    const expireTime = Date.now() - cacheExpireTime;

    try {
      // 查找所有过期的数据
      const expiredEntries = await ctx.database.get('day60s_image_cache', {
        insertTime: { $lt: expireTime }
      });

      if (expiredEntries.length > 0) {
        day60sLogger.info(`找到 ${expiredEntries.length} 条过期缓存，开始清理...`);
        // 批量删除过期数据
        const keywordsToRemove = expiredEntries.map(entry => entry.keyword);
        await ctx.database.remove('day60s_image_cache', { keyword: { $in: keywordsToRemove } });
        day60sLogger.info('清理完成。');
      } else {
        day60sLogger.info('没有找到需要清理的过期缓存。');
      }
    } catch (e) {
      day60sLogger.error(`清理缓存时出错: ${e.message}`);
    }
  }


  /**
   * 统一获取新闻数据和图片链接的辅助函数。
   * @param withImage 是否需要获取图片链接。
   * @returns 包含新闻文本和可选图片URL的数组。
   */
  async function getNewsData(withImage: boolean): Promise<NewsItemWithImage[]> {
    if (withImage) {
      await cleanUpExpiredImageCache();
    }

    const newsList = await getDay60sNews();
    const newsData: NewsItemWithImage[] = [];
    const now = Date.now();

    const findWorkingImageUrl = async (imageItems: any[]): Promise<string | undefined> => {
      // 遍历图片结果
      for (let i = 0; i < imageItems.length; i++) {
        const item = imageItems[i];
        if (!item.link) continue;
        const proxyLink = `${config.googleApi.baseUrl}/image_proxy?url=${item.link}`;
        day60sLogger.info(`尝试第 ${i} 张图片，URL: ${proxyLink}`);

        try {
          // 使用 httpx 客户端发起请求，检查图片是否可访问
          // 这里假设 ctx.http 是一个 httpx 实例或类似的 fetch 客户端
          const res = await ctx.http.get(proxyLink, {validateStatus: (status) => status === 503});

          // 检查响应状态码是否在成功范围内
          if (res.status !== 503) {
            day60sLogger.info(`找到可用的图片URL: ${proxyLink}`);
            return proxyLink;
          }
        } catch (e) {
          day60sLogger.info(`图片URL不可用，尝试下一个。URL: ${proxyLink}, 错误: ${e.message}`);
        }
      }
      return undefined;
    };

    for (const item of newsList) {
      let imageUrl: string | undefined = undefined;

      if (withImage) {
        const cachedImage = await ctx.database.get('day60s_image_cache', { keyword: item.text });

        if (item.text === '今天的简讯未更新，下面是昨天的简讯！') {
          imageUrl = undefined;
          day60sLogger.info(`跳过开头的${item.text}`);
        } else if (cachedImage.length > 0) {
          imageUrl = cachedImage[0].imageUrl;
          day60sLogger.info(`从缓存中获取图片，keyword: ${item.text}`);
        } else {
          try {
            const imageSearchRes = await getGoogleImages(
              ctx,
              config.googleApi.baseUrl,
              item.text,
              config.googleApi.apiKey,
              config.googleApi.searchEngineId,
              1,
              10,
              'zh-CN'
            );

            // 调用新函数来查找第一个可用的图片URL
            if (imageSearchRes?.items?.length > 0) {
              imageUrl = await findWorkingImageUrl(imageSearchRes.items);
            }

            if (imageUrl) {
              day60sLogger.info(`通过 API 获取到可用的图片，keyword: ${item.text}`);

              await ctx.database.create('day60s_image_cache', {
                keyword: item.text,
                imageUrl,
                insertTime: now
              });
              day60sLogger.info(`缓存图片链接成功，keyword: ${item.text}`);
            } else {
              day60sLogger.warn(`为新闻"${item.text}"未能找到可用图片.`);
            }
          } catch (e) {
            day60sLogger.error(`为新闻"${item.text}"获取图片失败. e.message = ${e.message}`);
          }
        }
      }

      newsData.push({
        text: item.text,
        // 使用代理 URL，即使没有找到图片，也不会抛出错误
        imageUrl: imageUrl ? `${config.googleApi.baseUrl}/image_proxy?url=${imageUrl}` : undefined,
      });
    }

    return newsData;
  }

  async function formatNewsAsTextWithImage(config: any, withGoogleImage: boolean): Promise<Array<h>> {
    const newsData = await getNewsData(withGoogleImage);
    let res: Array<h> = [];

    for (const item of newsData) {
      res.push(h.text(item.text.replace(/(\d、)/, '$1\t') + '\n'));
      if (item.imageUrl) {
        res.push(h.image(item.imageUrl));
      }
    }

    return res;
  }

  // 用于渲染新闻早报图片的HTML模板
  function getNewsImageHtmlTemplate(config: any, newsData: Array<NewsItemWithImage>, date: string): string {
    const isDarkMode = config.day60s.enablePuppeteerDarkImageMode;
    const colors = {
      bg: isDarkMode ? '#2a2a3a' : '#f0f0f0',
      cardBg: isDarkMode ? 'rgba(45, 45, 60, 0.7)' : 'rgba(255, 255, 255, 0.7)',
      cardBorder: isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
      cardShadow: isDarkMode ? 'rgba(0, 0, 0, 0.4)' : 'rgba(0, 0, 0, 0.15)',
      mainText: isDarkMode ? '#fff' : '#333',
      subText: isDarkMode ? '#ccc' : '#666',
      titleColor: isDarkMode ? '#5e81ac' : '#3d5c9e',
      newsNumberColor: isDarkMode ? '#5e81ac' : '#3d5c9e',
      separator: isDarkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)',
      newsSeparator: isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
      footerText: isDarkMode ? '#999' : '#888',
    };

    const newsItemsHtml = newsData.map(item => `
    <div class="news-item">
      <p class="news-text">${item.text.replace(/(\d+、)/, '<span class="news-number">$1</span>\t')}</p>
      ${item.imageUrl ? `<div class="news-image-container"><img class="news-image" src="${item.imageUrl}" onerror="this.style.display='none'" /></div>` : ''}
    </div>
  `).join('');

    return `
    <html>
    <head>
      <meta charset="utf-8" />
      <style>
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
        body{font-family:'Inter','Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;margin:0;padding:30px;background:${colors.bg};color:${colors.mainText}}
        .card{max-width:600px;margin:0 auto;border-radius:20px;overflow:hidden;background:${colors.cardBg};backdrop-filter:blur(15px)saturate(160%);-webkit-backdrop-filter:blur(15px)saturate(160%);border:1px solid ${colors.cardBorder};box-shadow:0 10px 30px ${colors.cardShadow};padding:25px;display:flex;flex-direction:column;gap:20px}
        .header{text-align:center;border-bottom:2px solid ${colors.separator};padding-bottom:15px}
        .title{font-size:2.2em;font-weight:700;margin:0;color:${colors.titleColor}}
        .subtitle{font-size:1.1em;color:${colors.subText};margin-top:5px}
        .news-item{display:flex;flex-direction:column;gap:10px;padding-bottom:15px;border-bottom:1px solid ${colors.newsSeparator}}
        .news-item:last-child{border-bottom:none;padding-bottom:0}
        .news-text{font-size:1.2em;line-height:1.6;color:${colors.mainText};margin:0}
        .news-number{font-weight:700;color:${colors.newsNumberColor};font-size:1.2em}
        .news-image-container{border-radius:12px;overflow:hidden;box-shadow:0 5px 15px rgba(0,0,0,0.3);width:90%;margin:0 auto;}
        .news-image{width:100%;height:auto;display:block;object-fit:cover}
        .footer{text-align:center;font-size:0.9em;color:${colors.footerText};margin-top:10px}
      </style>
    </head>
    <body>
      <div class="card">
        <div class="header">
          <div class="title">【60秒早报】</div>
          <div class="subtitle">每日新闻速览 - ${date}</div>
        </div>
        <div class="news-list">
          ${newsItemsHtml}
        </div>
        <div class="footer">
          ${POWERED_BY_STR}
        </div>
      </div>
    </body>
    </html>
  `;
  }

  async function formatNewsAsImage(config: any, withGoogleImage: boolean): Promise<Array<h>> {
    // 1. 获取新闻和图片数据
    const newsData = await getNewsData(withGoogleImage);

    // 2. 使用 Puppeteer 渲染图片
    if (!ctx.puppeteer) {
      throw new Error("Puppeteer 服务不可用。请确保已安装 koishi-plugin-puppeteer 插件。");
    }

    const page = await ctx.puppeteer.page();
    try {
      const htmlContent = getNewsImageHtmlTemplate(config, newsData, formatDateTime());

      await page.setViewport({ width: 700, height: 1 });
      await page.setContent(htmlContent, { waitUntil: 'domcontentloaded' });

      await page.waitForFunction(() => {
        const images = Array.from(document.querySelectorAll('.news-image')) as HTMLImageElement[];
        return images.every(img => img.complete);
      }, { timeout: 20000 });

      const cardElement = await page.$('.card');
      const boundingBox = await cardElement?.boundingBox();

      if (!boundingBox) {
        throw new Error('无法获取卡片元素的边界框。');
      }

      const screenshot = await page.screenshot({
        type: 'png',
        encoding: 'base64',
        clip: boundingBox
      });

      return [h.text('今天的60秒新闻：'), h.image(`data:image/png;base64,${screenshot}`)];
    } finally {
      await page.close();
    }
  }

  async function formatNewsAsForward(config: any, withGoogleImage: boolean): Promise<string> {
    try {
      // 1. 获取新闻和图片数据
      const newsData = await getNewsData(withGoogleImage);
      day60sLogger.info(` newsData = ${JSON.stringify(newsData)}`);

      let messages = '';

      // Helper to add a message block with author and content
      const addMessageBlock = (authorId: string | undefined, authorName: string, content: string) => {
        messages += `
          <message>
            <author ${authorId ? `id="${authorId}"` : ``} name="${authorName}"/>
            ${content}
          </message>`;
      };

      // First message: The title of the forward message
      addMessageBlock(
        undefined,
        '每日60秒新闻',
        `【每日60秒新闻】${formatDateTime()}`
      );

      // Subsequent messages: Each news item with an optional image
      for (let i = 0; i < newsData.length; i++) {
        const item = newsData[i];

        // Add the news text message block
        addMessageBlock(
          `【No.${i + 1}】文字`,
          `【No.${i + 1}】文字`,
          item.text.replace(/(\d+、)/, `<b>$1</b>`)
        );

        // Add a separate image message block if an image exists
        if (item.imageUrl) {
          addMessageBlock(
            `【No.${i + 1}】图片`,
            `【No.${i + 1}】图片`,
            h.image(item.imageUrl).toString()
          );
        }
      }
      return `<message forward>\n${messages}\n</message>`;
    } catch (e) {
      day60sLogger.error(`生成合并转发消息失败: ${e.message}`);
      throw e;
    }
  }


  // 定时任务相关
  const day60sCronTaskArr: ScheduledTask[] = [];

  // 导出的函数：注册所有定时任务
  function startCronTasks(ctx: Context, config: any) {
    const day60sLogger = new Logger(`${PLUGIN_NAME}-day60s`);

    if (!config.day60s.enableCronTask || !config.day60s.cronTaskChannelList?.length) {
      day60sLogger.info('定时任务未启用或配置为空。');
      return;
    }

    day60sLogger.info('开始注册定时任务...');
    for (const taskConfig of config.day60s.cronTaskChannelList) {
      try {
        const { platform, channelId, cronExp, messageForm, withGoogleImage } = taskConfig;

        const job = cron.schedule(cronExp, async () => {
          day60sLogger.info(`定时任务触发，向频道 ${platform}:${channelId} 发送早报。`);

          let newsMessage;

          if (messageForm === MESSSAGE_FORM.TEXT) {
            newsMessage = await formatNewsAsTextWithImage(config, withGoogleImage);
          } else if (messageForm === MESSSAGE_FORM.IMAGE) {
            newsMessage = await formatNewsAsImage(config, withGoogleImage);
          } else if (messageForm === MESSSAGE_FORM.FORWARD) {
            newsMessage = await formatNewsAsForward(config, withGoogleImage);
          }

          const platformBot = ctx.bots.find(bot => bot.platform === platform);
          await platformBot.sendMessage(channelId, newsMessage);
        }, {
          timezone: "Asia/Shanghai" // 设定时区，确保时间正确
        });

        day60sCronTaskArr.push(job);
        day60sLogger.info(`已成功注册定时任务：${platform}:${channelId}，Cron表达式: ${cronExp}`);

      } catch (e) {
        day60sLogger.error(`注册定时任务失败，请检查配置。错误: ${e.message}`);
      }
    }
  }

  // 导出的函数：取消所有定时任务
  function stopCronTasks() {
    const day60sLogger = new Logger(`${PLUGIN_NAME}-day60s`);
    if (!day60sCronTaskArr.length) {
      day60sLogger.info('没有需要停止的定时任务。');
      return;
    }

    day60sLogger.info(`共找到 ${day60sCronTaskArr.length} 个定时任务，开始停止...`);
    for (const job of day60sCronTaskArr) {
      job.stop();
    }
    // 清空数组
    day60sCronTaskArr.length = 0;
    day60sLogger.info('所有定时任务已成功停止。');
  }

  // 在插件准备就绪时注册定时任务
  ctx.on('ready', () => {
    startCronTasks(ctx, config);
  });

  // 在插件被注销时停止定时任务
  ctx.on('dispose', () => {
    stopCronTasks();
  });

}



